﻿using log4net.Layout;
using log4net.Layout.Pattern;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common.Msg
{
    public class OperatorUser
    {
        /// <summary>
        /// 操作用户ID
        /// </summary>
        public int OperatorID { get; set; } = 10;

        /// <summary>
        /// 操作用户姓名
        /// </summary>
        public string OperatorName { get; set; } = "";

        /// <summary>
        /// 操作项目
        /// </summary>
        public string OperProject { get; set; } = "";

        /// <summary>
        /// 用户IP
        /// </summary>
        public string IP { get; set; } = "";

        /// <summary>
        /// 浏览器
        /// </summary>
        public string Browser { get; set; } = "";

        /// <summary>
        /// 机器名
        /// </summary>
        public string MachineName { get; set; } = "";
    }
    public class CustomLogger
    {
        private static log4net.ILog logger;
        private static bool isLogInfo = Files.ConfigFileHelper.GetConfigSetting("InfoLog") == "true";
        private static bool isLogWarn = Files.ConfigFileHelper.GetConfigSetting("WarnLog") == "true";
        /// <summary>
        /// 动作类型
        /// </summary>
        public enum ActionType
        {
            登录 = 1,
            退出 = 2,
            新增 = 3,
            编辑 = 4,
            删除 = 5,
            查询 = 6,
            导出Excel = 7
        }

        /// <summary>
        /// 操作状态
        /// </summary>
        public enum OperStatus
        {
            //未处理
            Untreated = 1,
            //成功
            Success = 2,
            //失败
            Fail = 3
        }



        static CustomLogger()
        {
            new Common.Msg.MyLayout();
            string baseDir = System.AppDomain.CurrentDomain.BaseDirectory;
            System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(baseDir, "log4net.config"));
            log4net.Config.XmlConfigurator.Configure(file);
            //logger = log4net.LogManager.GetLogger("myName");
            logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        }
        /// <summary>
        /// 记录系统异常日志
        /// </summary>
        /// <param name="methodName">异常来源方法名称</param>
        /// <param name="customMsg">自定义错误消息</param>
        /// <param name="ex">系统异常</param>
        public static void Error(string methodName, string customMsg = "", System.Exception ex = null)
        {
            logger.Error(new LogContent("", methodName, customMsg), ex);
        }
        public static void Error(string methodName, string customMsg = "", ActionType actionType = ActionType.新增, OperStatus operStatus = OperStatus.Untreated, OperatorUser operatorUser = null, System.Exception ex = null)
        {
            logger.Error(GetLogContent(methodName, customMsg, actionType, operStatus, operatorUser), ex);
        }
        /// <summary>
        /// 记录系统信息
        /// </summary>
        /// <param name="methodName">操作方法名称</param>
        /// <param name="content">信息</param>
        public static void Info(string methodName, string content)
        {
            if (isLogInfo)
                logger.Info(new LogContent("", methodName, content));
        }
        public static void Info(string methodName, string customMsg = "", ActionType actionType = ActionType.新增, OperStatus operStatus = OperStatus.Untreated, OperatorUser operatorUser = null)
        {
            if (isLogInfo)
                logger.Info(GetLogContent(methodName, customMsg, actionType, operStatus, operatorUser));
        }
        /// <summary>
        /// 记录系统警告信息
        /// </summary>
        /// <param name="methodName">操作方法名称</param>
        /// <param name="content">信息</param>
        public static void Warn(string methodName, string content)
        {
            if (isLogWarn)
                logger.Warn(new LogContent("", methodName, content));
        }
        public static void Warn(string methodName, string customMsg = "", ActionType actionType = ActionType.新增, OperStatus operStatus = OperStatus.Untreated, OperatorUser operatorUser = null)
        {
            if (isLogWarn)
                logger.Warn(GetLogContent(methodName, customMsg, actionType, operStatus, operatorUser));
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="message"></param>
        /// <param name="actionType"></param>
        /// <param name="operStatus"></param>
        /// <param name="operatorUser"></param>
        /// <returns></returns>
        private static LogContent GetLogContent(string methodName, string message, ActionType actionType = ActionType.新增, OperStatus operStatus = OperStatus.Untreated, OperatorUser operatorUser = null)
        {
            LogContent logContent = (LogContent)operatorUser;
            logContent.MethodName = methodName;
            logContent.Message = message;
            logContent.ActionType = (int)actionType;
            logContent.OperStatus = (int)operStatus;
            return logContent;
        }
    }
    /// <summary>
    /// 包含了所有的自定字段属性
    /// </summary>
    internal class LogContent : OperatorUser
    {
        public LogContent(string operatorName, string methodName, string message)
        {
            this.OperatorName = operatorName;
            this.MethodName = methodName;
            this.Message = message;
        }

        /// <summary>
        /// 操作方法名称
        /// </summary>
        public string MethodName { get; set; } = "";

        /// <summary>
        /// 动作类型
        /// </summary>
        public int ActionType { get; set; } = 0;

        /// <summary>
        /// 日志描述信息
        /// </summary>
        public string Message { get; set; } = "";

        /// <summary>
        /// 操作状态
        /// </summary>
        public int OperStatus { get; set; } = 0;

        /// <summary>
        /// 操作时间
        /// </summary>
        public DateTime OperTime { get; set; } = DateTime.Now;
    }
    internal class MyLayout : PatternLayout
    {
        public MyLayout()
        {
            this.AddConverter("property", typeof(LogInfoPatternConverter));
        }
    }

    internal class LogInfoPatternConverter : PatternLayoutConverter
    {
        protected override void Convert(System.IO.TextWriter writer, log4net.Core.LoggingEvent loggingEvent)
        {
            if (Option != null)
            {
                // Write the value for the specified key
                WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent));
            }
            else
            {
                // Write all the key value pairs
                WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties());
            }
        }
        /// <summary>
        /// 通过反射获取传入的日志对象的某个属性的值
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        private object LookupProperty(string property, log4net.Core.LoggingEvent loggingEvent)
        {
            object propertyValue = string.Empty;
            System.Reflection.PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property);
            if (propertyInfo != null)
                propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null);
            return propertyValue;
        }
    }
}
